<template>
  <div class="root" id="root" ref="rootRef">
    <div class="control-box">
      <div class="progress-box">
        <div class="duration">
          <span>{{ currentTime }}</span>
          <span>00:00</span>
        </div>
        <div class="progress"></div>
      </div>
      <div class="control">
        <div class="video-name">温馨美好小清新古风视频</div>
        <div class="control-main">
          <div class="action">后退</div>
          <div class="action" @click="handlePlay">播放/暂停</div>
          <div class="action">快进</div>
        </div>
        <div class="video-settings">
          <select class="select" v-model="playbackRate" placeholder="倍速" @change="changePlaybackRate">
              <option :value="0.5" label="倍速X0.5"/>
              <option :value="1" label="倍速X1"/>
              <option :value="1.5" label="倍速X1.5"/>
              <option :value="2" label="倍速X2"/>
              <option :value="2.5" label="倍速X2.5"/>
              <option :value="3" label="倍速X3"/>
              <option :value="3.5" label="倍速X3.5"/>
              <option :value="4" label="倍速X4"/>
          </select>
          <select class="select" v-model="activateFilter" placeholder="滤镜" @change="changeFilter">
              <option value="reset" label="无滤镜"/>
              <option value="sepia" label="sepia"/>
              <option value="negative" label="negative"/>
              <option value="kodachrome" label="kodachrome"/>
              <option value="lsd" label="lsd"/>
              <option value="polaroid" label="polaroid"/>
              <option value="contrast" label="contrast"/>
              <option value="grayscale" label="grayscale"/>
              <option value="predator" label="predator"/>
              <option value="saturate" label="saturate"/>
              <option value="desaturate" label="desaturate"/>
          </select>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { Application, Container, Sprite, Texture, TextureSource, Assets, Graphics, ColorMatrixFilter, BlurFilter , type FederatedPointerEvent } from 'pixi.js';
import { PixelateFilter, KawaseBlurFilter, BackdropBlurFilter } from 'pixi-filters'
const props = defineProps({
  url: {
    type: String,
    default: ''
  }
})
const rootWidth = ref<number>(0)
const rootHeight = ref<number>(0)
const rootRef = ref<HTMLElement>() // 将pixi应用渲染到的节点
const videoRef = ref<HTMLVideoElement>() // 视频节点
const currentTime = ref<number|string>('00:00')
const playbackRate = ref<number>(1) // 播放倍速

const app = shallowRef<Application>(new Application()) // pixi应用
const rootContainer = shallowRef<Container>(new Container()) // pixi应用根容器
const videoContainer = shallowRef<Container>(new Container()) // pixi应用视频精灵容器
const videoSprite = shallowRef<Sprite>(new Sprite()) // pixi视频层精灵
const mskGraphics = shallowRef<Graphics>(new Graphics()) // 图形马赛克

const colorMatrixFilter = shallowRef<ColorMatrixFilter>(new ColorMatrixFilter())
const activateFilter = ref<string>('reset') // 当前滤镜
const kawaseBlurFilter = new KawaseBlurFilter({
  strength: 4,
  quality: 50,
  clamp: true,
  pixelSize: [2,1]
})
const backdropBlurFilter = new BackdropBlurFilter({
  strength: 1,
  quality: 2,
  kernelSize: 13,
})
const blurFilter = new BlurFilter()
watch(() => props.url, async (nUrl) => {
  if(nUrl) renderVideo();
})

// 渲染pixi应用
async function renderApp() {
 
  await app.value.init({
    resizeTo: rootRef.value,
    antialias: true, // 抗锯齿
  })
  rootRef.value?.appendChild(app.value.canvas);
  app.value.stage.addChild(rootContainer.value) // 向app中添加根容器
  rootContainer.value.addChild(videoContainer.value) // 向跟容器中添加视频容器
  videoContainer.value.addChild(videoSprite.value) // 向视频容器中添加视频精灵
  videoContainer.value.filters = [colorMatrixFilter.value]
  videoContainer.value.eventMode = 'static' // 设置视频容器可点击
  // 监听视频容点击事件
  videoContainer.value.on('click', (event:  FederatedPointerEvent) => {
    console.log('======', event)
  })
  createMSK();
  renderVideo();
}
 
// 向视频精灵上添加视频 isCanPlay：boolean 是否可以播放不可以播放展示第一帧
async function addVideo(isCanPlay: boolean = false) {
  if(isCanPlay) {
    const videoTexture = TextureSource.from(videoRef.value!)
    videoTexture.width = rootWidth.value
    videoTexture.height = rootHeight.value
    videoSprite.value.texture = Texture.from(videoTexture)
  } else {
    videoSprite.value.texture = await Assets.load({
      src: props.url,
      data: { preload: 'none', autoplay: false },
      loadParser :'loadVideo'
    });
  }
  videoSprite.value.position.set(0,0)
  videoSprite.value.setSize(rootWidth.value, rootHeight.value)
}
// 创建马赛克形状
function createMSK() {
  mskGraphics.value = new Graphics();
  
  mskGraphics.value.filters = [blurFilter]
  videoContainer.value.addChild(mskGraphics.value)
}
// 渲染视频
async function renderVideo() {
  videoRef.value = document.createElement('video')
  videoRef.value.src = props.url;
  videoRef.value.autoplay = true;
  videoRef.value.muted = true;
  videoRef.value.onplay = () => {
    videoRef.value!.muted = false;
  }
  let x=100, y=100;
  videoRef.value.ontimeupdate = () => {
    currentTime.value = videoRef.value!.currentTime.toFixed(2)
    x+=20,y+=5;
    mskGraphics.value.clear()
    // 符合条件时添加马赛克
    if( videoRef.value!.currentTime<=2 || videoRef.value!.currentTime>=2.5) {
      mskGraphics.value.beginPath()
      mskGraphics.value.moveTo(x, y);
      mskGraphics.value.ellipse(x, y, 50, 60);
      mskGraphics.value.stroke({color: 0xffffff, width: 30})
      mskGraphics.value.closePath()
      mskGraphics.value.filters = [new PixelateFilter([50,60])]
    }
  }
  videoRef.value.oncanplay = () => {
    addVideo(true)
  }
}
// 监听窗口尺寸发生改变
function onResize() {
  if(rootRef.value) {
    rootWidth.value = rootRef.value.clientWidth
    rootHeight.value = rootRef.value.clientHeight
    videoSprite.value.setSize(rootWidth.value, rootHeight.value)
    videoContainer.value.setSize(rootWidth.value, rootHeight.value)
    rootContainer.value.setSize(rootWidth.value, rootHeight.value)
  }
}
function handlePlay() {
  if(videoRef.value?.paused) {
    videoRef.value?.play()
  } else {
    videoRef.value?.pause()
  }
}
// 改变播放速度
function changePlaybackRate() {
  if(videoRef.value) {
    videoRef.value.playbackRate = playbackRate.value
  }
}
// 改变滤镜
function changeFilter() {
  const oneParams = ['sepia', 'negative', 'kodachrome', 'lsd', 'polaroid']
  const noParams = ['saturate', 'desaturate', 'reset']
  colorMatrixFilter.value.reset()
  if(noParams.includes(activateFilter.value)) {
    ( colorMatrixFilter.value as any)[activateFilter.value]()
  } else if(oneParams.includes(activateFilter.value)) {
    ( colorMatrixFilter.value as any)[activateFilter.value](true)
  } else {
    ( colorMatrixFilter.value as any)[activateFilter.value](0.5, false)
  }
}
async function onInit() {
  await nextTick();
  onResize();
  await renderApp();
}
onMounted(async () => {
  onInit();
  window.addEventListener('resize', onResize)
})

onUnmounted(() => {
  window.removeEventListener('resize', onResize)
})
</script>
<style lang="scss" scoped>
.root {
  position: relative;
  width: 100%;
  height: 100%;
  z-index: inherit;
  .control-box {
    position: absolute;
    z-index: 1000;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 50px;
    
    padding: 0;
    display: flex;
    flex-direction: column;
    .progress-box {
      width: 100%;
      .duration {
        padding: 0 20px;
        display: flex;
        justify-content: space-between;
        align-items: flex-end;
        color: #fff;
      }
      .progress {
        width: 100%;
        height: 5px;
        background: #ddd;
      }
    }
    .control {
      background: rgba(0,0,0,.6);
      flex: 1;
      display: flex;
      flex-direction: row;
      justify-content: space-between;
      align-items: center;
      padding: 0 20px;
      .select {
        width: 40px;
        height: 16px;
        border-radius: 3px;
        outline: none;
        color: #ffffff;
        background: transparent;
        option {
          background: #333;
        }
      }
      .control-main {
        display: flex;
        flex-direction: row;
        color: #fff;
        .action {
          margin: 0 10px;
          border-radius: 10px;
          border:1px solid #f7f7f7;
          padding: 3px 6px;
          cursor: pointer;
        }
      }
      .video-name {
        display: flex;
        flex-direction: row;
        align-items: center;
        height: 100%;
        width: 100px;
        color: #fff;
      }
      .video-settings {
        display: flex;
        flex-direction: row-reverse;
        align-items: center;
        height: 100%;
        width: 100px;
      }
    }

  }
}
</style>